#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <string.h>
// 　头文件stdio.h包含了目录文件操作．
//  fopen,fprintf,fscanf,fseek,ftell,fwrite,fread，fclose
//  fprintf就跟printf类似，输出到文件。优点明文。
//  fopen打开目录文件
//  fseek配置文件中要操作的位置。
//  ftell当前操作的位置。
//  fwrite写入文件。
//  fread读文件。
//  fgets读一行，需要明文。
//  fclose 关闭文件。
// 　fflush 系统会将写入文件的数据放到内存缓存区，后面才会写入硬盘。如果要立即同步到硬盘的文件，用fflush。fflush(stdout);立即输出到终端。
// fgetc //从文件获取一个字符．　getc从终端获取一个字符．
// fputc 输出一个字符到文件，　putc输出字符到终端．
// remove 删除文件
// 　rename　文件重命名．

// fopen打开标志。
//  r
//  以只读方式打开文件，该文件必须存在。
//  r+
//  以读/写方式打开文件，该文件必须存在。
//  rb+
//  以读/写方式打开一个二进制文件，只允许读/写数据。
//  rt+
//  以读/写方式打开一个文本文件，允许读和写。
//  w
//  打开只写文件，若文件存在则文件长度清为零，即该文件内容会消失；若文件不存在则创建该文件。
//  w+
//  打开可读/写文件，若文件存在则文件长度清为零，即该文件内容会消失；若文件不存在则创建该文件。
//  a
//  以附加的方式打开只写文件。若文件不存在，则会创建该文件；如果文件存在，则写入的数据会被加到文件尾后，即文件原先的内容会被保留（EOF 符保留）。
//  a+
//  以附加方式打开可读/写的文件。若文件不存在，则会创建该文件，如果文件存在，则写入的数据会被加到文件尾后，即文件原先的内容会被保留（EOF符不保留）。
//  wb
//  以只写方式打开或新建一个二进制文件，只允许写数据。
//  wb+
//  以读/写方式打开或新建一个二进制文件，允许读和写。
//  wt+
//  以读/写方式打开或新建一个文本文件，允许读和写。
//  at+
//  以读/写方式打开一个文本文件，允许读或在文本末追加数据。
//  ab+
//  以读/写方式打开一个二进制文件，允许读或在文件末追加数据。

// printf其实也是输出到stdout文件．stdout就是我们的终端输出．
// 　scanf其实是从文件stdin输入，stdin就是我们的终端输入．
// perror 输出到stderr,默认也是终端．
// #define stdin stdin  系统自动打开，文件描述符时0
// #define stdout stdout 系统自动打开，文件描述符时1
// #define stderr stderr 系统自动打开，文件描述符时2

// 　文件ｗ或ｒ打开文件，操作文件的光标在0位置．
// 　a打开文件，操作文件的光标在末尾．
// 　如果需要修改文件的某一段数据，可以r+方式打开文件(因为ｗ会清空文件)，把光标指定到对应位置然后修改．但不能插入数据．．
//  一般我们是把文件数据先读取到内存，删添改操作完成，再写回去．

#define MY_FILE_CHECK_PATH_NAME "/tmp/myChkFile.txt"
// 测试fprintf, fscanf
int fchekPrint(const char *fpath)
{ // check file fprintf.
    //  "w+",打开可读/写文件，若文件存在则文件长度清为零，即该文件内容会消失；若文件不存在则创建该文件。
    FILE *tmpfile = fopen(fpath, "w+");
    int tmpint = 1234;
    char tmpstr[16] = "inputstr";
    int tmpflag = -1;
    printf("--->check file fprintf function\n");
    if (!tmpfile)
    {
        printf("open file fail:%s\n", fpath);
        return -1;
    }
    do
    {
        // use fprintf() write string to file.
        // printf,fprintf, sprintf,返回输出的最终字符串长度．
        tmpflag = fprintf(tmpfile, "intVal=%d,strval=%s", tmpint, tmpstr);
        if (tmpflag < 1)
        {
            perror("fprintf fail!"); // perror 自动添加\n
            break;                   // 退出循环，文件已经打开了，需要关闭！
        }
        // fwrite已经将操作位置写到最后，需要读取fwrite写入的数据，需要配置操作光标。
        fseek(tmpfile, 0, SEEK_SET);
        tmpint = -1;
        memset(tmpstr, 0, sizeof(tmpstr));
        // 　scanf,fscanf,sscanf,返回获得几个参数．这里我们需要获取tmpint/tmpstr两个数据，因此正常返回时２．
        tmpflag = fscanf(tmpfile, "intVal=%d,strval=%s", &tmpint, tmpstr);
        if (tmpflag != 2)
        {
            perror("fscanf fail!"); // perror 自动添加\n
            break;                  // 退出循环，文件已经打开了，需要关闭！
        }
        printf("read ok intval=%d,strval=%s\n", tmpint, tmpstr);
    } while (0);
    fclose(tmpfile);
    return 0; // use cat /tmp/myChkFile.txt check file info
}
// 测试fwrite,fread
int fchekWrite(const char *fpath)
{
    //  "w+",打开可读/写文件，若文件存在则文件长度清为零，即该文件内容会消失；若文件不存在则创建该文件。
    FILE *tmpfile = fopen(fpath, "w+");
    int tmpint = 1234;
    char tmpstr[16] = "inputstr";
    int tmpflag = -1;
    char tmpWrStr[128];
    printf("--->check file fwrite function\n");
    if (!tmpfile)
    {
        printf("open file fail:%s\n", fpath);
        return -1;
    }
    do
    {
        // use fwrite() write string to file.
        // fwrite,返回输出的最终字符串长度．
        tmpflag = snprintf(tmpWrStr, sizeof(tmpWrStr), "intVal=%d,strval=%s", tmpint, tmpstr);
        if (tmpflag < 1)
        {
            perror("fprintf fail!"); // perror 自动添加\n
            break;                   // 退出循环，文件已经打开了，需要关闭！
        }
        tmpflag = fwrite(tmpWrStr, 1, tmpflag, tmpfile);
        printf("fwrite result=%d\n", tmpflag);
        // fwrite已经将操作位置写到最后，需要读取fwrite写入的数据，需要配置操作光标。
        fseek(tmpfile, 0, SEEK_SET);
        tmpint = -1;
        memset(tmpstr, 0, sizeof(tmpstr));
        // fread返回实际读取长度．
        tmpflag = fread(tmpWrStr, 1, sizeof(tmpWrStr), tmpfile);
        if (tmpflag < 1)
        {
            perror("fscanf fail!"); // perror 自动添加\n
            break;                  // 退出循环，文件已经打开了，需要关闭！
        }
        sscanf(tmpWrStr, "intVal=%d,strval=%s", &tmpint, tmpstr);
        printf("read ok intval=%d,strval=%s\n", tmpint, tmpstr);
    } while (0);
    fclose(tmpfile);
    return 0; // use cat /tmp/myChkFile.txt check file info
}

// 测试fputs
int fchekPuts(const char *fpath)
{
    //  "w+",打开可读/写文件，若文件存在则文件长度清为零，即该文件内容会消失；若文件不存在则创建该文件。
    FILE *tmpfile = fopen(fpath, "w+");
    char tmpWrStr[256];
    printf("--->check file fputs function\n");
    if (!tmpfile)
    {
        printf("open file fail:%s\n", fpath);
        return -1;
    }
    do
    {
        // fputs不自动换行．
        fputs("file check fputs function!\n", tmpfile);
        fputs("file check fputs 2 string!\n", tmpfile);
        // fputs已经将操作位置写到最后，需要读取写入的数据，需要配置操作光标。
        fseek(tmpfile, 0, SEEK_SET);
        while (fgets(tmpWrStr, sizeof(tmpWrStr), tmpfile))
        {
            printf("fgets ok: %s\n", tmpWrStr); // 因为读取的行数据有\n,这里又打印了\n，输出有两个回车！
        }
    } while (0);
    fclose(tmpfile);
    return 0; // use cat /tmp/myChkFile.txt check file info
}

// 测试append
int fchekAppend(const char *fpath, const char *appendStr)
{
    //  "a+",打开可读/写文件，不清空文件内容，打开后，光标在末尾，直接追加数据．
    FILE *tmpfile = fopen(fpath, "a+");
    printf("--->check file append function:%s\n", appendStr);
    if (!tmpfile)
    {
        printf("open file fail:%s\n", fpath);
        return -1;
    }
    do
    {
        fprintf(tmpfile, "%s\n", appendStr);
    } while (0);
    fclose(tmpfile);
    return 0; // use cat /tmp/myChkFile.txt check file info
}

int main(int argc, char **argv)
{
    {
        fchekPrint(MY_FILE_CHECK_PATH_NAME);
    }
    {
        fchekWrite(MY_FILE_CHECK_PATH_NAME);
    }
    {
        fchekPuts(MY_FILE_CHECK_PATH_NAME);
    }
    {
        fchekAppend(MY_FILE_CHECK_PATH_NAME, "my check string 1");
        fchekAppend(MY_FILE_CHECK_PATH_NAME, "my check string 2");
        fchekAppend(MY_FILE_CHECK_PATH_NAME, "my check string 3");
        //　然后使用cat /tmp/myChkFile.txt　查看输出文件结果．
    }
    return 1;
}
